﻿using System;
using System.Collections;
using System.Linq;
using System.Collections.Generic;
using LinearAlgebra.MatrixAlgebra;
namespace LinearAlgebra.VectorAlgebra
{
    public enum VectorType
    {
        /// <summary>
        /// 行向量
        /// </summary>
        Row,
        /// <summary>
        /// 列向量
        /// </summary>
        Column
    };
    public sealed class Vector : IEquatable<Vector>, IEnumerable<double>
    {
        double[] elements;
        public double[] Elements { get { return elements; } set { elements = value; } }
        VectorType vType;
        public VectorType vectorType { get { return vType; } set { vType = value; } }
        public int Count { get { return elements.Length; } }
        public double this[int index] { get { return elements[index]; } set { elements[index] = value; } }
        public Vector(double[] _elements, VectorType _vectorType)
        {
            elements = _elements;
            vType = _vectorType;
        }
        public Vector(VectorType _vectorType, params double[] _elements) : this(_elements, _vectorType)
        {

        }

        #region 隐式转换
        public static implicit operator Vector(Matrix m)
        {
            if (m.ColumnCount == 1)
            {
                var ele = m.GetColumn(0);
                return new Vector(ele.ToArray(), VectorType.Column);
            }
            else if (m.RowCount == 1)
            {
                var ele = m.GetRow(0);
                return new Vector(ele.ToArray(), VectorType.Row);
            }
            else
            {
                throw new ArgumentException("只有单行/单列的矩阵才能转化为向量");
            }
        }

        #endregion

        #region 基本运算
        public static Vector operator +(Vector X)
        {
            return new Vector(X.elements.CopyVector(), X.vType);
        }
        public static Vector operator -(Vector X)
        {
            return VectorComputation.UnaryMinus(X);
        }
        public static Vector operator +(Vector X, Vector Y)
        {
            return VectorComputation.Add(X, Y);
        }
        public static Vector operator +(Vector X, double Scalar)
        {
            return VectorComputation.Add(X, Scalar);
        }
        public static Vector operator -(Vector X, Vector Y)
        {
            return VectorComputation.Subtract(X, Y);
        }
        public static Vector operator -(Vector X, double Scalar)
        {
            return VectorComputation.Subtract(X, Scalar);
        }
        public static Vector operator -(double Scalar, Vector X)
        {
            return VectorComputation.Subtract(Scalar, X);
        }

        public static Vector operator *(Vector X, Vector Y)
        {
            return VectorComputation.Multiply(X, Y);
        }
        public static Vector operator *(Vector X, double Scalar)
        {
            return VectorComputation.Multiply(X, Scalar);
        }
        public static Vector operator *(double Scalar, Vector X)
        {
            return VectorComputation.Multiply(X, Scalar);
        }

        public static Vector operator /(Vector X, Vector Y)
        {
            return VectorComputation.Divide(X, Y);
        }
        public static Vector operator /(Vector X, double Scalar)
        {
            return X * (1 / Scalar);
        }
        #endregion

        public Vector Map(Func<double, double> func)
        {
            return VectorComputation.Map(this, func);
        }
        public static double DotProduct(Vector X, Vector Y)
        {
            return VectorComputation.DotProduct(X, Y);
        }
        public static Vector RowVecMulMat(Vector X, Matrix Y)
        {
            return VectorMatrixComputation.RowVectorMultiplyMatrix(X, Y);
        }
        public static Matrix ColVecMulMat(Vector X, Matrix Y)
        {
            return VectorMatrixComputation.ColumnVectorMultiplyMatrix(X, Y);
        }
        public static Matrix MatMulRowVec(Matrix X, Vector Y)
        {
            return VectorMatrixComputation.MatrixMultiplyRowVector(X, Y);
        }
        public static Vector MatMulColVec(Matrix X, Vector Y)
        {
            return VectorMatrixComputation.MatrixMultiplyColumnVector(X, Y);
        }
        public override string ToString()
        {
            if (vType == VectorType.Row) return string.Format("[ {0} ]", string.Join("  ", elements));
            else return string.Format("[ {0} ]", string.Join("\r\n", elements));
        }
        public string ToString(string template)
        {
            if (vType == VectorType.Row) return string.Format("[ {0:{1}} ]", string.Join("  ", elements), template);
            else return string.Format("[ {0}:{1} ]", string.Join("\r\n", elements), template);
        }

        /// <summary>
        /// 比较类型和各分量
        /// </summary>
        public bool Equals(Vector other)
        {
            const double eps = 1e-09;
            if (vType != other.vType) return false;
            int n = Count;
            if (n != other.Count) return false;
            unsafe
            {
                fixed (double* x = elements)
                fixed (double* y = other.elements)
                    for (int i = 0; i < n; i++)
                        if (Math.Abs(x[i] - y[i]) > eps)
                            return false;
            }
            return true;
        }

        public override bool Equals(object obj)
        {
            if (obj == null || !(obj is Vector)) return false;
            return Equals(obj as Vector);
        }

        /// <summary>
        /// 生成序列
        /// </summary>
        /// <param name="start">第一个分量的值</param>
        /// <param name="count">向量维度</param>
        /// <param name="step">步长</param>
        public static Vector Range(VectorType _vectorType, double start, int count, double step = 1.0)
        {
            var v = new double[count];
            for (int i = 0; i < count; i++, start += step)
                v[i] = start;
            return new Vector(v, _vectorType);
        }
        public IEnumerator<double> GetEnumerator()
        {
            foreach (var item in elements) yield return item;
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            foreach (var item in elements) yield return item;
        }

        public static Vector Random(int count, VectorType type)
        {
            return Random(count, type, new Random());
        }

        public static Vector Random(int count, VectorType type, Random rnd)
        {
            double[] vect = new double[count];
            unsafe
            {
                fixed (double* v = vect)
                    for (int i = 0; i < count; i++)
                    {
                        v[i] = rnd.NextDouble();
                    }
            }
            return new Vector(vect, type);
        }

        #region 特殊向量
        /// <summary>
        /// [0,0,0...]
        /// </summary>
        public static Vector Zero(int count, VectorType type)
        {
            return new Vector(new double[count], type);
        }

        /// <summary>
        /// [1,1,1....]
        /// </summary>
        public static Vector One(int count, VectorType type)
        {
            double[] Z = new double[count];
            unsafe
            {
                fixed (double* z = Z)
                    for (int i = 0; i < count; i++)
                    {
                        z[i] = 1;
                    }
            }
            return new Vector(Z, type);
        }
        #endregion
    }
}
